#include "ortho_camera.h"

OrthoCamera::OrthoCamera(Point eye,Point at,Point up,const Cube& viewVolume)
	:	_viewVolume(viewVolume){
	_eye = eye;
	_at = at;
	_up = up;

	float m = sqrt(pow(_up.x1,2)+pow(_up.x2,2));
	yztheta = atan2(_up.x3,m);
	xytheta = atan2(_up.x1,_up.x2);
}

OrthoCamera::~OrthoCamera(){}

void OrthoCamera::applyCamera(){
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	glOrtho(	_viewVolume.vertices()[4].x1,_viewVolume.vertices()[2].x1,
				_viewVolume.vertices()[4].x2,_viewVolume.vertices()[2].x2,
				_viewVolume.vertices()[4].x3,_viewVolume.vertices()[2].x3);

	applyModelViewTransformations();
}

void OrthoCamera::move(float offset){
	Point aheadDir = (this->getEye()-this->getAt());
	aheadDir.x3 = 0;
	Point move = aheadDir*offset;
	Matrix4x4 m(move.x1,move.x2,move.x3);

	this->_eye = m*this->_eye;
	this->_at = m*this->_at;
}

void OrthoCamera::rotate(float theta){
	theta = theta*PI/180;

	Matrix4x4 m(-xytheta,Point(0,0,1));
	Matrix4x4 r2(-yztheta,Point(1,0,0));
	Matrix4x4 r3(theta,Point(0,0,1));
	Matrix4x4 r4(yztheta,Point(1,0,0));
	Matrix4x4 r5(xytheta,Point(0,0,1));

	m*=r2;
	m*=r3;
	m*=r4;
	m*=r5;

	// En este tipo de proyeccion no existe otro tipo
	// de rotacion posible de la camara
	_up = m*_up;
	xytheta += theta;
}

void OrthoCamera::applyModelViewTransformations(){
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	Point eye = this->getEye();
	Point at = this->getAt();
	Point up = this->getUp();
	gluLookAt(eye.x1, eye.x2, eye.x3, at.x1, at.x2, at.x3, up.x1, up.x2, up.x3);
}

void OrthoCamera::updatePosition(const Point& position,const Point& direction,PathInfo* info){
	this->_eye = position;
	this->_at = position+direction;
}

bool OrthoCamera::isBoxVisible(const Cube& box)const{
	Cube translatedViewVolume = _viewVolume;
	translatedViewVolume.translate(_eye.x1,_eye.x2,0);
	return translatedViewVolume.intersect(box);
}
